package com.base.cn.platform.os.service.statistics.base;

import com.base.cn.platform.os.common.mybatis.BaseBiz;
import com.base.cn.platform.os.common.utils.DateUtils;
import com.base.cn.platform.os.common.utils.ObjectUtils;
import com.base.cn.platform.os.common.utils.StringUtils;
import com.base.cn.platform.os.dao.order.order.OrderDao;
import com.base.cn.platform.os.dao.statistics.base.ZStatisticsOrderBaseCountDao;
import com.base.cn.platform.os.entity.order.order.Order;
import com.base.cn.platform.os.entity.statistics.base.StatisticsDateQueryCondition;
import com.base.cn.platform.os.entity.statistics.base.ZStatisticsOrderBaseCount;
import com.base.cn.platform.os.entity.statistics.pvuv.ZStatisticsUniqueVisitorCount;
import com.base.cn.platform.os.service.statistics.pvuv.ZStatisticsUniqueVisitorCountBiz;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * 基础统计中的交易基础数据统计Biz
 *
 * @author s.li
 * @date 2019/04/18
 */
@Service
public class ZStatisticsOrderBaseCountBiz extends BaseBiz<ZStatisticsOrderBaseCount, ZStatisticsOrderBaseCountDao> {
    private static final String TIME_FORMAT = "yyyy-MM-dd";
    private static final String TIME_FORMAT_H = "yyyy-MM-dd HH";
    @Autowired
    private OrderDao orderDao;
    @Autowired
    private ZStatisticsUniqueVisitorCountBiz zStatisticsUniqueVisitorCountBiz;

    private DecimalFormat decimalFormat = new DecimalFormat("#.##");

    /**
     * 查询两个时间段内的非免费订单每天的统计数据总量
     * @param  dateList 时间列表
     * @return  ZStatisticsOrderBaseCount 数据总量
     */
    public ZStatisticsOrderBaseCount queryOrderTimeSlotDayCountSum(List<Date> dateList){
        Map<String,String> params = new HashMap<>();
        params.put("timeSql",StatisticsDateQueryCondition.getTimeSql(dateList,TIME_FORMAT));
        ZStatisticsOrderBaseCount sumOrderBaseCount = orderDao.queryOrderTimeSlotDayCountSum(Order.class,params);
        if(sumOrderBaseCount==null){
            sumOrderBaseCount = new ZStatisticsOrderBaseCount();
        }
        return sumOrderBaseCount;
    }

    /**
     * 获取订单统计数据
     * @param dateQueryCondition 是查询的时间条件对象
     * @return List<ZStatisticsOrderBaseCount>
     */
    public List<ZStatisticsOrderBaseCount> queryOrderBaseCountList(StatisticsDateQueryCondition dateQueryCondition){
        List<ZStatisticsOrderBaseCount> orderBaseCountList;
        //时间列表（每天一个元素）
        List<Date> dateList = dateQueryCondition.getDayList();
        //时间类型，1=今日实时，2=近7天（不包含当天），3=近30天（不包含当天），4=自定义（只可选当天之前的时间，且时间跨度不超过12月） 5=昨日
        if(dateQueryCondition.getType()==1 || dateList.size() ==1){
            //获取当前时间对象
            Date nowDate;
            if(dateQueryCondition.getType()==1){
                nowDate =  new Date();
            }else{
                dateQueryCondition.setType(1);
                nowDate = dateList.get(0);
            }
            //格式分时间
            String nowTime = DateUtils.format(nowDate,TIME_FORMAT);
            //获取当天的订单数据列表
            orderBaseCountList = orderDao.queryOrderOneDayCountList(Order.class,nowTime);
            //当天的访问量（UV）
            ZStatisticsUniqueVisitorCount uniqueVisitorCount = zStatisticsUniqueVisitorCountBiz.getOneDayUniqueVisitorCount(nowDate);
            //把当前的时间拆解成24个小时
            List<Date> _dateList = DateUtils.getDay24HourList(nowDate);
            if(ObjectUtils.isNotEmpty(orderBaseCountList)){//如果当天有订单
                //以小时为Key转成Map
                Map<String,ZStatisticsOrderBaseCount> orderBaseCountMap = orderBaseCountList.stream().collect(Collectors.toMap(e->DateUtils.format(e.getCountTime(),TIME_FORMAT_H),e->e));
                List<ZStatisticsOrderBaseCount> newList = new ArrayList<>();
                IntStream.range(0,_dateList.size()).forEach(index->{
                    Date date = _dateList.get(index);
                    String key = DateUtils.format(date,TIME_FORMAT_H);
                    ZStatisticsOrderBaseCount orderBaseCount = orderBaseCountMap.get(key);
                    if(orderBaseCount==null){//如果某个小时中没有统计数据，则生成一条默认的记录
                        orderBaseCount = new ZStatisticsOrderBaseCount();
                        orderBaseCount.setCountTime(date);
                        newList.add(orderBaseCount);
                    }
                    if(index==0){
                        //设置UV人数
                        orderBaseCount.setVisitorCount(uniqueVisitorCount.getRequestCount());
                    }
                });
                if(ObjectUtils.isNotEmpty(newList)){
                    orderBaseCountList.addAll(newList);
                }
            }else{//如果当天没有订单
                List<ZStatisticsOrderBaseCount> _orderBaseCountList = new ArrayList<>();
                IntStream.range(0,_dateList.size()).forEach(index->{
                    Date date = _dateList.get(index);
                    ZStatisticsOrderBaseCount orderBaseCount = new ZStatisticsOrderBaseCount();
                    orderBaseCount.setCountTime(date);
                    _orderBaseCountList.add(orderBaseCount);
                    if(index==0){//在第一条数据中设置UV量
                        orderBaseCount.setVisitorCount(uniqueVisitorCount.getRequestCount());
                    }
                });
                orderBaseCountList = _orderBaseCountList;
            }
        }else{
            //查询当前的统计表
            orderBaseCountList = this.find( "countTime in "+ StatisticsDateQueryCondition.getTimeSql(dateList,TIME_FORMAT),null,null);

            //如果有统计过
            if(ObjectUtils.isNotEmpty(orderBaseCountList)){
                //以时间（天）为K，转成Map
                Map<String,ZStatisticsOrderBaseCount> orderBaseCountMap = orderBaseCountList.stream().collect(Collectors.toMap(e->DateUtils.format(e.getCountTime(),TIME_FORMAT),e->e));
                List<Date> conditionDataList = new ArrayList<>();
                //处理时间，查找到没有统计记录的时间段（天）
                dateList.forEach(date->{
                    ZStatisticsOrderBaseCount orderBaseCount = orderBaseCountMap.get(DateUtils.format(date,TIME_FORMAT));
                    if(orderBaseCount==null){//某天的统计数据未生成，则把时间记录起来
                        conditionDataList.add(date);
                    }
                });
                if(ObjectUtils.isNotEmpty(conditionDataList)){//如果有未生成的时间统计数据，则去查询未保存
                    List<ZStatisticsOrderBaseCount> _orderBaseCountList = this.getOrderBaseCountList(conditionDataList);
                    if(ObjectUtils.isNotEmpty(_orderBaseCountList)){
                        orderBaseCountList.addAll(_orderBaseCountList);
                    }
                }
            }else{
                orderBaseCountList = this.getOrderBaseCountList(dateList);
            }
        }

        if(ObjectUtils.isNotEmpty(orderBaseCountList)){
            //重新排序
            Collections.sort(orderBaseCountList, new Comparator<ZStatisticsOrderBaseCount>() {
                @Override
                public int compare(ZStatisticsOrderBaseCount o1, ZStatisticsOrderBaseCount o2) {
                    o1.setCreateTime(null);
                    o2.setCreateTime(null);
                    o1.setUpdateTime(null);
                    o2.setUpdateTime(null);
                    return o1.getCountTime().after(o2.getCountTime())? 1:-1;
                }
            });
        }
        return orderBaseCountList;
    }

    /**
     * 从订单表中查询统计数据，未把数据保存到统计表中，并且返回数据
     * @param dateList 时间列表
     * @return  List<ZStatisticsOrderBaseCount>
     */
    private List<ZStatisticsOrderBaseCount> getOrderBaseCountList(List<Date> dateList){
        Map<String,String> params = new HashMap<>();
        params.put("timeSql",StatisticsDateQueryCondition.getTimeSql(dateList,TIME_FORMAT));
        List<ZStatisticsOrderBaseCount> addList = new ArrayList<>();
        //从订单表中统计出新数据列表
        List<ZStatisticsOrderBaseCount> orderBaseCountList = orderDao.queryOrderTimeSlotDayCountList(Order.class,params);
        if(ObjectUtils.isNotEmpty(orderBaseCountList)){
            //以时间为Key转成Map
            Map<String,ZStatisticsUniqueVisitorCount> uniqueVisitorCountMap = this.uniqueVisitorCountMap(dateList);

            //以时间为Key转成Map
            Map<String,ZStatisticsOrderBaseCount> orderBaseCountMap = orderBaseCountList.stream().collect(Collectors.toMap(e->DateUtils.format(e.getCountTime(),TIME_FORMAT),e->e));
            dateList.forEach(date->{
                String key = DateUtils.format(date,TIME_FORMAT);
                ZStatisticsOrderBaseCount orderBaseCount = orderBaseCountMap.get(key);
                if(orderBaseCount==null){//如果在指定的天中没有统计数据，则生成一条统计数据
                    orderBaseCount = new ZStatisticsOrderBaseCount();
                    orderBaseCount.setCountTime(date);
                    orderBaseCountList.add(orderBaseCount);
                }
                //设置访问量
                this.setVisitorCount(uniqueVisitorCountMap,key,orderBaseCount);
                //设置数据（付费转化率、客单价、下单转化率、付款转化率、平台转化率）
                this.setData(orderBaseCount);
            });
            //把新统计出来的数据保存到统计表中
            addList.addAll(orderBaseCountList);
        }else{
            List<ZStatisticsOrderBaseCount> _orderBaseCountList = new ArrayList<>();
            //以时间为Key转成Map
            Map<String,ZStatisticsUniqueVisitorCount> uniqueVisitorCountMap = this.uniqueVisitorCountMap(dateList);
            //生成没有统计数据记录对象
            dateList.forEach(date->{
                ZStatisticsOrderBaseCount orderBaseCount = new ZStatisticsOrderBaseCount();
                orderBaseCount.setCountTime(date);
                String key = DateUtils.format(date,TIME_FORMAT);
                //设置访问量
                this.setVisitorCount(uniqueVisitorCountMap,key,orderBaseCount);
                //设置数据（付费转化率、客单价、下单转化率、付款转化率、平台转化率）
                this.setData(orderBaseCount);
                //添加数据到列表中
                _orderBaseCountList.add(orderBaseCount);
            });
            addList.addAll(_orderBaseCountList);
        }
        //数据保存
        if(ObjectUtils.isNotEmpty(addList)){
            this.batchSave(addList);
        }
        return addList;
    }

    /**
     * 设置数据
     * @param orderBaseCount 统计数据对象
     */
    private void setData(ZStatisticsOrderBaseCount orderBaseCount){
        //付费转化率
        Float payConversionRate = new Float(orderBaseCount.getPayUserCount()) / new Float(orderBaseCount.getVisitorCount());

        if(payConversionRate.isNaN() || payConversionRate.isInfinite()){
            payConversionRate = 0.00f;
        }
        orderBaseCount.setPayConversionRate(Float.parseFloat(decimalFormat.format(payConversionRate*100f)));

        //客单价（平均人消费）
        Double averageAmount = orderBaseCount.getPayAmount() / orderBaseCount.getPayUserCount();
        if(averageAmount.isNaN() || averageAmount.isInfinite()){
            averageAmount = 0.00d;
        }
        orderBaseCount.setAverageAmount(Double.parseDouble(decimalFormat.format(averageAmount)));

        //下单转化率
        Float orderRate = new Float(orderBaseCount.getOrderCount()) / new Float(orderBaseCount.getVisitorCount());
        if(orderRate.isNaN() || orderRate.isInfinite()){
            orderRate = 0.00f;
        }
        orderBaseCount.setOrderRate(Float.parseFloat(decimalFormat.format(orderRate*100f)));

        //付款转化率 payRate
        Float payRate = new Float(orderBaseCount.getPayUserCount()) / new Float(orderBaseCount.getOrderCount());
        if(payRate.isNaN() || payRate.isInfinite()){
            payRate = 0.00f;
        }
        orderBaseCount.setPayRate(Float.parseFloat(decimalFormat.format(payRate*100f)));

        //平台转化率 userPayRate
        Float userPayRate = new Float(orderBaseCount.getPayUserCount()) / new Float(orderBaseCount.getVisitorCount());
        if(userPayRate.isNaN() || userPayRate.isInfinite()){
            userPayRate = 0.00f;
        }
        orderBaseCount.setUserPayRate(Float.parseFloat(decimalFormat.format(userPayRate*100f)));
    }

    /**
     * 设置访问量
     * @param uniqueVisitorCountMap UV数据Map
     * @param key 时间KEY
     * @param orderBaseCount 订单统计数据
     */
    private void setVisitorCount(Map<String,ZStatisticsUniqueVisitorCount> uniqueVisitorCountMap,String key,ZStatisticsOrderBaseCount orderBaseCount){
        if(ObjectUtils.isNotEmpty(uniqueVisitorCountMap) && StringUtils.isNotEmpty(key) && orderBaseCount!=null){
            ZStatisticsUniqueVisitorCount uniqueVisitorCount = uniqueVisitorCountMap.get(key);
            if(ObjectUtils.isNotEmpty(uniqueVisitorCount)){//设置访问量
                orderBaseCount.setVisitorCount(uniqueVisitorCount.getRequestCount());
            }
        }
    }

    /**
     * 获取某个时间段内的UV数据
     * @param dateList 时间段列表
     * @return Map<String,ZStatisticsUniqueVisitorCount>
     */
    private Map<String,ZStatisticsUniqueVisitorCount> uniqueVisitorCountMap(List<Date> dateList){
        //以时间为Key转成Map
        Map<String,ZStatisticsUniqueVisitorCount> uniqueVisitorCountMap = new HashMap<>();
        //查询某个时间段内的每天的UV量（访问量）
        List<ZStatisticsUniqueVisitorCount> uniqueVisitorCountList = zStatisticsUniqueVisitorCountBiz.find(" requestTime in "+StatisticsDateQueryCondition.getTimeSql(dateList,TIME_FORMAT),null,null);
        if(ObjectUtils.isNotEmpty(uniqueVisitorCountList)){
            uniqueVisitorCountMap.putAll(uniqueVisitorCountList.stream().collect(Collectors.toMap(e->DateUtils.format(e.getRequestTime(),TIME_FORMAT),e->e)));
        }
        return uniqueVisitorCountMap;
    }

}
